#include <algorithm>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <string>

#include "Appointment_t.h"
#include "Calendar_t.h"

Calendar_t::Calendar_t()
{
	// TODO
}

Calendar_t::~Calendar_t()
{
	removeAll();
}

Calendar_t::Calendar_t(const Calendar_t& other)
{
	// TODO
}

Calendar_t& Calendar_t::operator=(const Calendar_t& other)
{
	// TODO
	return *this;
}

bool Calendar_t::insert(Appointment_t* const appointment)
{
	if(intersects(*appointment))
		return false; // Appointment found

	// Insert appointment
	m_appointments.insert(std::make_pair(appointment->startTime(), appointment));
	return true;
}

bool Calendar_t::remove(const Appointment_t& appointment, bool deletePtr)
{
	AppointmentsContainer::iterator it = m_appointments.find(appointment.startTime());
	if(it == m_appointments.end())
		return false; // Appointment not found

	// Delete if requested
	if(deletePtr)
		delete it->second;

	// Remove appointment
	m_appointments.erase(it);
	return true;
}

void Calendar_t::removeAll(bool deletePtrs)
{
	if(deletePtrs)
	{
		// Delete each appointment ptr
		AppointmentsContainer::iterator it = m_appointments.begin();
		for(; it != m_appointments.end(); it++)
			delete it->second;
	}

	// Clear appointments
	m_appointments.clear();
}

Appointment_t* Calendar_t::find(const DayTime_t& startTime) const
{
	AppointmentsContainer::const_iterator it = m_appointments.find(startTime);
	if(it == m_appointments.end())
		return NULL; // Appointment not found

	// Return found appointment
	return it->second;
}

bool Calendar_t::duplicate(const Appointment_t& appointment, 
						   const DayTime_t& startTime,
						   const DayTime_t& endTime)
{
	// Clone given appointment
	Appointment_t* clone = appointment.clone();

	// Set time
	if(!clone->setTime(startTime, endTime))
		return false;

	// Attempt insertion
	if(!insert(clone))
	{
		delete clone;
		return false;
	}

	return true;
}

/*
void Calendar_t::print2() const{
	int width=8;
	std::ostringstream os;
	os.fill(' ');
	os<<std::setw(width)<<std::left<<" ";
	os<<std::setw(width)<<std::left<<"|Sun";
	os<<std::setw(width)<<std::left<<"|Mon";
	os<<std::setw(width)<<std::left<<"|Tue";
	os<<std::setw(width)<<std::left<<"|Wed";
	os<<std::setw(width)<<std::left<<"|Thu";
	os<<std::setw(width)<<std::left<<"|Fri";
	os<<std::setw(width)<<std::left<<"|Sat";
	os<<"|";
	os<<std::endl;
	os.fill('-');

	std::ostringstream** days=new std::ostringstream*[7];
	std::string** strings = new std::string*[7];
	for(int d=0; d<7; d++)
	{
		days[d]=new std::ostringstream;
		strings[d] = new std::string;
	}

	for(int d=0; d<7; d++)
	{
		std::ostringstream& day=*(days[d]);
		int duration = 0;
		for(int h=0; h<24; h++)
		{
			std::string appStr="|";

			Appointment_t* app = find((Day_t)(d+1),h);
			if(app!=NULL)
			{
				appStr+=app->getSubject();
				duration = app->endTime()-app->startTime();
			}
			day.fill(' ');
			day<<std::setw(width)<<std::left<<appStr;
			day<<std::endl;
			if(duration > 0)
			{
				day.fill(' ');
				duration--;
			}
			else
			{
				day.fill('-');
			}
			day<<std::setw(width)<<std::left<<"-";
			day<<std::endl;
		}
		*strings[d] += day.str();
	}

	char h='0', hh='0';
	for(int i=0; i<48; i++)
	{
		std::string str="";
		std::string hour="|";
		if(i%2 == 0)
		{
			if(i/2>=10 && i/2<20)
				h='1';
			if(i/2>=20)
				h='2';
			hour+=h; hour+=hh; hour+=":00";
		}
		else
		{
			hour+="-------";
		}
		std::ostringstream oshour;
		oshour<<std::setw(width)<<std::left<<hour;

		str+=oshour.str();

		for(int j=0; j<7; j++)
		{
			std::string& s = *strings[j];
			int p=s.find_first_of('\n');
			str += s.substr(0,p);
			s = s.substr(p+1,s.size()-p+1);
		}

		os<<str<<"|"<<std::endl;
		if(i%2 == 0)
			hh=(hh=='9')?'0':(hh+1);
	}


	std::cout<<os.str();

	for(int d=0; d<7; d++)
	{
		delete days[d];
		delete strings[d];
	}
	delete[] days;
	delete[] strings;

}
*/

/*
void Calendar_t::print() const
{
	// TODO
	int width=8;
	std::ostringstream os;
	os.fill(' ');
	os<<std::setw(width)<<std::left<<" ";
	os<<std::setw(width)<<std::left<<"|Sun";
	os<<std::setw(width)<<std::left<<"|Mon";
	os<<std::setw(width)<<std::left<<"|Tue";
	os<<std::setw(width)<<std::left<<"|Wed";
	os<<std::setw(width)<<std::left<<"|Thu";
	os<<std::setw(width)<<std::left<<"|Fri";
	os<<std::setw(width)<<std::left<<"|Sat";
	os<<"|";
	os<<std::endl;
	os.fill('-');
	os<<std::setw(width*8);
	os<<"|";
	os<<"|";
	os<<std::endl;

	os.fill(' ');
	char h='0', hh='0';

	// create line for every hour
	for(int i=0; i<24; i++)
	{
		if(i>=10 && i<20)
			h='1';
		if(i>=20)
			h='2';
		std::string hour="|";
		hour+=h; hour+=hh; hour+=":00";
		os<<std::setw(width)<<std::left<<hour;

		// fill column for each day in the given hour
		for(int j=1; j<8; j++)
		{
			std::string appStr="|";

			Appointment_t* app = find((Day_t)j,i);
			if(app!=NULL)
			{
				appStr+=app->getSubject();
			}
			os<<std::setw(width)<<std::left<<appStr;
		}

		os<<std::endl;

		os.fill('-');
		os<<std::setw(width*8);
		os<<"|";
		os<<"|";
		os<<std::endl;
		os.fill(' ');

		hh=(hh=='9')?'0':(hh+1);
	}
	std::cout<<os.str();
}
*/

bool Calendar_t::intersects(const Appointment_t& appointment) const
{
	// Find appointment
	AppointmentsContainer::const_iterator it = m_appointments.begin();
	for(; it != m_appointments.end(); it++)
	{
		if(*it->second == appointment)
			return true;
	}

	return false;
}